home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Simulation / PDP-8 Simulator / Source Code / PDPRunner.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-20  |  10.6 KB  |  445 lines  |  [TEXT/KAHL]

  1. /*************************************************************************************
  2. *
  3. *        PDP-8 Simulation Program- cpu simulator
  4. *
  5. *        ©1992 Graham Cox. All Rights Reserved.
  6. *
  7. *        Modification History:
  8. *        9/3/92 created from scratch.    
  9. *
  10. *
  11. *
  12. *************************************************************************************/
  13.  
  14. #include    "PDPGlobalEqu.p"
  15.  
  16. #include "PDPRunner.proto.h"
  17.  
  18. PDPMemHdl        GetMemory(WindowPtr theWindow);
  19. PDPRegHdl        GetCPU(WindowPtr theWindow);
  20. PrefsRecHdl        GetPrefs(WindowPtr theWindow);
  21. ProcessRecHdl    GetProcess(WindowPtr theWindow);
  22. ControlHandle    GetMemScrollbar(WindowPtr theWindow);
  23. char            PDPProcHalted(WindowPtr pW);
  24.  
  25.  
  26. int        CycleProcess(WindowPtr targetProcess)
  27. {
  28.     /* high level call to execute one machine cycle of target process. Window must be of
  29.         correct kind. Process is extracted from window, instruction at PC location is
  30.         fetched and executed, and the PC is incremented. If an error occurred, the code
  31.         is returned. This procedure is called repeatedly to run a PDP-8 program */
  32.         
  33.     PDPMemHdl    procMemory;
  34.     PDPRegHdl    procCPU;
  35.     int            pdpErr;
  36.     
  37.     if (IsSimulator(targetProcess)) {
  38.         procMemory = GetMemory(targetProcess);
  39.         procCPU = GetCPU(targetProcess);
  40.         
  41.         if (procMemory != NIL) {
  42.             if (procCPU != NIL) {
  43.                 pdpErr = FetchInstruction(procCPU,procMemory);
  44.                 if (! pdpErr) {
  45.                     pdpErr = ExecuteInstruction(procCPU,procMemory);
  46.                     RefreshSimWindow(targetProcess);
  47.                 }
  48.                 return(pdpErr);    
  49.             }
  50.             else
  51.                 return(TargetHasNoProcessor);
  52.         }
  53.         else
  54.             return(TargetHasNoMemory);
  55.     }
  56. }
  57.  
  58.  
  59. int FetchInstruction(PDPRegHdl theCPU,PDPMemHdl theMemory)
  60. {
  61.     /* gets the instruction from the location in simulated memory pointed to by the PC in
  62.         the processor, and places it in the processors Instruction Register (IR) */
  63.         
  64.     PDPWord        address;
  65.     PDPMemPtr    memLoc;
  66.     
  67.     address = (*theCPU)->PC;
  68.     if (address < 4097 && address >=0) {
  69.         memLoc = *theMemory + address;
  70.         (*theCPU)->IR = (*memLoc & 0x0FFF);
  71.         return(noErr);
  72.     }
  73.     return(CPUAddressingError);
  74. }
  75.  
  76.  
  77. int    ExecuteInstruction(PDPRegHdl theCPU,PDPMemHdl theMemory)
  78. {
  79.     /* decodes the current instruction (in IR) and calls procedures to execute each one
  80.         accordingly. The contents of the ACC, PC and EAR are likely to be changed. The IR
  81.         is left unchanged. If an error occurs, the procedure aborts and returns the code */
  82.     
  83.     Byte        opCode,addressMode;
  84.     short        operand,pdpErr;
  85.     PDPWord        Instruction;
  86.     PDPMemPtr    memLoc;
  87.     
  88.     Instruction = (*theCPU)->IR;
  89.     opCode = (Instruction & opcodeMask) >> 9;
  90.     operand = Instruction & operandMask;
  91.     addressMode = (Instruction & addressModeMask) >> 7;
  92.     
  93.     /* decode & execute */
  94.     
  95.     if (opCode < pdpACC) {
  96.         /* explicit addressing operations, calculate effective address (EAR) */
  97.         
  98.         if (addressMode & pageBit)
  99.             /* relative address on current page */
  100.             
  101.             (*theCPU)->EAR = ((*theCPU)->PC & topFiveBits) | operand;
  102.         else
  103.             /* page zero address, top five bits are zero */
  104.             
  105.             (*theCPU)->EAR = operand;
  106.  
  107.         if (addressMode & indirectBit) {
  108.             /* indirect addressing- fetch indirect address. This is the address in the
  109.                 location pointed to by the EAR. */
  110.             
  111.             memLoc = *theMemory + (*theCPU)->EAR;
  112.             (*theCPU)->EAR = (*memLoc & 0x0FFF);
  113.         }
  114.         /* EAR now contains the destination address, which is the target address of the
  115.             current opcode, so decode opcode and perform required operation */
  116.             
  117.         pdpErr = DecodeExplicit(opCode,theCPU,theMemory);
  118.     }
  119.     else 
  120.         /* accumulator operations- implicit addressing. Group Bit is in addressMode Byte */
  121.         
  122.         pdpErr = DecodeImplicit(operand,addressMode & 2,theCPU);
  123.     
  124.     /* increment program counter so we are pointing at the next instruction */
  125.     
  126.     (*theCPU)->PC ++;
  127.         
  128.     (*theCPU)->PC &= 0x0FFF;
  129.     return(pdpErr);    
  130. }
  131.  
  132.  
  133. int    DecodeExplicit(Byte opCode,PDPRegHdl theCPU,PDPMemHdl theMemory)
  134. {
  135.     /* executes given opcode, which must be between 0 and 6 */
  136.  
  137.     PDPWord        effectiveAddr;
  138.     PDPMemPtr    targLocation;
  139.     int            cpuErr;
  140.     
  141.     if (opCode >= pdpAND && opCode<pdpACC) {
  142.         effectiveAddr = (*theCPU)->EAR;
  143.  
  144.         if (effectiveAddr >=0 && effectiveAddr < 4096) {
  145.             HLock((Handle) theMemory);
  146.             targLocation = *theMemory + effectiveAddr;
  147.             cpuErr = noErr;
  148.             switch(opCode) {
  149.                 case pdpAND:
  150.                     (*theCPU)->ACC &= (*targLocation & 0x0FFF);    /* MEM & ACC -> ACC */
  151.                     break;
  152.                 case pdpTAD:
  153.                     (*theCPU)->ACC += *targLocation;            /* ACC + MEM -> ACC */
  154.                     (*theCPU)->ACC &= 0x0FFF;
  155.                     break;
  156.                 case pdpISZ:
  157.                     *targLocation +=1;                            /* MEM -> MEM+1, IF MEM=0 THEN SKIP */
  158.                     *targLocation &= 0x0FFF;
  159.                     if (*targLocation ==0)
  160.                         (*theCPU)->PC +=1;
  161.                     cpuErr = MemWriteUpdateRequest;
  162.                     break;
  163.                 case pdpDCA:
  164.                     *targLocation = (*theCPU)->ACC & 0x0FFF;    /* ACC -> MEM, 0 -> ACC */
  165.                     (*theCPU)->ACC = 0;    
  166.                     cpuErr = MemWriteUpdateRequest;
  167.                     break;
  168.                 case pdpJMS:
  169.                     *targLocation = (*theCPU)->PC+1 & 0x0FFF;    /* PC -> MEM, EAR -> PC */ 
  170.                     (*theCPU)->PC = effectiveAddr;
  171.                     cpuErr = MemWriteUpdateRequest;
  172.                     break;
  173.                 case pdpJMP:
  174.                     (*theCPU)->PC = effectiveAddr -1;            /* EAR-1 -> PC */
  175.                     break;
  176.                 case pdpIO:
  177.                     *targLocation = (*theCPU)->ACC;                /* ACC -> MEM, MEM -> ACC */
  178.                     (*theCPU)->ACC = *targLocation;
  179.                     cpuErr = MemWriteUpdateRequest;
  180.                     break;
  181.             }
  182.             HUnlock((Handle) theMemory);
  183.             return(cpuErr);
  184.         }
  185.         else
  186.             return(CPUAddressingError);
  187.     }
  188.     else
  189.         return(IllegalInstruction);
  190. }
  191.  
  192.  
  193. int    DecodeImplicit(int operation,Byte Group,PDPRegHdl theCPU)
  194. {
  195.     /* executes given implicit operations, in order of priority if multiple operations required */
  196.     
  197.     Byte        skipSense;
  198.     
  199.     if (Group) {
  200.         /* Group 2 instructions */
  201.         skipSense = operation & pdpRBit;
  202.         
  203.         if (operation & pdpSMA) {
  204.             if (skipSense) {
  205.                 if (!(*theCPU)->ACC & 0x0800)
  206.                     (*theCPU)->PC ++;
  207.             }
  208.             else {
  209.                 if ((*theCPU)->ACC & 0x0800)
  210.                     (*theCPU)->PC ++;
  211.             }
  212.         }
  213.         if (operation & pdpSZA) {
  214.             if (skipSense) {
  215.                 if (!(*theCPU)->ACC == 0)
  216.                     (*theCPU)->PC ++;
  217.             }
  218.             else {
  219.                 if ((*theCPU)->ACC == 0)
  220.                     (*theCPU)->PC ++;
  221.             }
  222.         }
  223.         if (operation & pdpSNL) {
  224.             if (skipSense) {
  225.                 if (!(*theCPU)->CCR & Link)
  226.                     (*theCPU)->PC ++;
  227.             }
  228.             else {
  229.                 if ((*theCPU)->CCR & Link)
  230.                     (*theCPU)->PC ++;
  231.             }
  232.         }
  233.         if (operation & pdpCLA)
  234.             (*theCPU)->ACC = 0;
  235.         if (operation & pdpHLT) {
  236.             (*theCPU)->CCR |= HaltBit;
  237.             (*theCPU)->PC --;
  238.             return(ProcessHalted);
  239.         }
  240.     }
  241.     else {
  242.         /* Group 1 instructions */
  243.         
  244.         if (operation & pdpCLA)
  245.             (*theCPU)->ACC =0;                            /* 0 -> ACC */
  246.         if (operation & pdpCLL)
  247.             (*theCPU)->CCR &= 0xFE;                        /* 0 -> L */
  248.         if (operation & pdpCMA)
  249.             (*theCPU)->ACC ^= 0x0FFF;                    /* -ACC -> ACC */
  250.         if (operation & pdpCML)
  251.             (*theCPU)->CCR ^= 1;                        /* -L -> L */
  252.         if (operation & pdpIAC) {
  253.             (*theCPU)->ACC +=1;                            /* ACC+1 -> ACC */
  254.             (*theCPU)->ACC &= 0x0FFF;
  255.         }
  256.         if (operation & pdpRBit) {
  257.             RotateAndLink(theCPU,rotateRight);
  258.             if (operation & pdpCBit)
  259.                 RotateAndLink(theCPU,rotateRight);
  260.         }
  261.         if (operation & pdpLBit) {
  262.             RotateAndLink(theCPU,rotateLeft);
  263.             if (operation & pdpCBit)
  264.                 RotateAndLink(theCPU,rotateLeft);
  265.         }
  266.             
  267.     }
  268.     return(noErr);
  269. }
  270.  
  271.  
  272. RotateAndLink(PDPRegHdl theCPU,Byte direcSense)
  273. {
  274.     /* rotates cpu accumulator through the link bit one place in the direction specified */
  275.     
  276.     PDPWord        tempAcc;
  277.     
  278.     tempAcc = (*theCPU)->ACC;
  279.     if (direcSense) {
  280.         /* going right */
  281.         tempAcc |= ((*theCPU)->CCR & Link) << 12;
  282.         (*theCPU)->CCR &= 0xFE;
  283.         (*theCPU)->CCR |= (tempAcc & 1);
  284.         tempAcc >>= 1;
  285.     }
  286.     else {
  287.         /* going left */
  288.         tempAcc <<= 1;
  289.         tempAcc |= ((*theCPU)->CCR & Link);
  290.         (*theCPU)->CCR &= 0xFE;
  291.         (*theCPU)->CCR |= (tempAcc & 0x1000) >> 12;
  292.     }    
  293.     (*theCPU)->ACC = (tempAcc & 0x0FFF);
  294. }
  295.  
  296.  
  297. RunPDP(WindowPtr wListHead)
  298. {
  299.     /* call repeatedly (once per event loop) to execute a PDP-8 program for this window.
  300.         If process halted, does nothing. Executes at a speed according to preferences
  301.         for this process. If error occurs, error reported and halt bit set. If single
  302.         step, does nothing (use Single Step procedure) */
  303.         
  304.     PrefsRecHdl        thePrefs;
  305.     PDPRegHdl        theCPU;
  306.     long            cTicks;
  307.     int                pdpErr;
  308.     WindowPtr        targetWindow;
  309.     
  310.     targetWindow = wListHead;
  311.     while (targetWindow != NIL) {
  312.         if (IsSimulator(targetWindow)) {
  313.             thePrefs = GetPrefs(targetWindow);
  314.             if (thePrefs != NIL){
  315.                 cTicks = TickCount();
  316.                 if ((*thePrefs)->cycleTime + (*thePrefs)->CPUSpeed < cTicks) {
  317.                     (*thePrefs)->cycleTime = cTicks;
  318.                     
  319.                     theCPU = GetCPU(targetWindow);
  320.                     
  321.                     if (theCPU != NIL) {
  322.                         if (!((*theCPU)->CCR & HaltBit || (*thePrefs)->CPUSpeed ==-1)) {
  323.                             pdpErr = CycleProcess(targetWindow);
  324.                             
  325.                             if (pdpErr) {
  326.                                 if (pdpErr == MemWriteUpdateRequest)
  327.                                     /* redraw the affected location */
  328.                                     UpdateMemoryLocation(targetWindow);
  329.                                 else {
  330.                                     ShowProcessError(pdpErr,GetProcessID(targetWindow));
  331.                                     StopPDP(targetWindow);
  332.                                 }
  333.                             }
  334.                         }
  335.                     }
  336.                 }
  337.             }
  338.         }
  339.         targetWindow = (*(WindowPeek)targetWindow).nextWindow;
  340.     }
  341. }
  342.  
  343.  
  344. StepPDP(WindowPtr targetWindow)
  345. {
  346.     /* executes a single cycle of target process */
  347.     
  348.     int                pdpErr;
  349.     PrefsRecHdl        thePrefs;
  350.     
  351.     if (IsSimulator(targetWindow)) {
  352.         pdpErr = CycleProcess(targetWindow);
  353.         /*
  354.         ScrollToPC(targetWindow);
  355.         */    
  356.         if (pdpErr) {
  357.             if (pdpErr == MemWriteUpdateRequest)
  358.                 /* redraw the affected location */
  359.                 UpdateMemoryLocation(targetWindow);
  360.             else {
  361.                 ShowProcessError(pdpErr,GetProcessID(targetWindow));
  362.                 StopPDP(targetWindow);
  363.             }
  364.         }    
  365.     }
  366. }
  367.  
  368.  
  369. StopPDP(WindowPtr targetWindow)
  370. {
  371.     /* halts processor in target window */
  372.     
  373.     PDPRegHdl    theCPU;
  374.     GrafPtr        savePort;
  375.     
  376.     if (IsSimulator(targetWindow)) {
  377.         theCPU = GetCPU(targetWindow);
  378.         HaltProcessor(theCPU);
  379.         GetPort(&savePort);
  380.         SetPort(targetWindow);
  381.         SetInverseClip(targetWindow);
  382.         DrawStatusBar(targetWindow,theCPU);
  383.         UnClipWindow(targetWindow);
  384.         SetPort(savePort);
  385.     }
  386. }
  387.  
  388.  
  389. ResetPDP(WindowPtr targetWindow)
  390. {
  391.     /* starts processor in target window. Sets PC to start Vector, and clears other regs */
  392.     
  393.     PDPRegHdl    theCPU;
  394.     PrefsRecHdl    thePrefs;
  395.     
  396.     if (IsSimulator(targetWindow)) {
  397.         thePrefs = GetPrefs(targetWindow);
  398.         theCPU = GetCPU(targetWindow);
  399.         (*theCPU)->PC = (*thePrefs)->DefaultStart & 0x0FFF;
  400.         (*theCPU)->ACC = 0;
  401.         (*theCPU)->IR = 0;
  402.         (*theCPU)->EAR = 0;
  403.         (*theCPU)->CCR &= 0xFE;
  404.         RefreshSimWindow(targetWindow);
  405.     }
  406. }
  407.  
  408.  
  409. ResumePDP(WindowPtr targetWindow)
  410. {
  411.     PDPRegHdl    theCPU;
  412.     
  413.     if (IsSimulator(targetWindow)) {
  414.         theCPU = GetCPU(targetWindow);
  415.         StartProcessor(theCPU);
  416.         SetInverseClip(targetWindow);
  417.         DrawStatusBar(targetWindow,theCPU);
  418.         UnClipWindow(targetWindow);
  419.     }
  420. }
  421.  
  422. #define    ProcErrorAlertID    132
  423. #define    ErrorStringsID        129
  424.  
  425. ShowProcessError(int errorID,int ProcessID)
  426. {
  427.     /* displays alert box with error message. */
  428.         
  429.     Str255        message;
  430.     Str32        idNum,pID;
  431.     int            aHit,messageID;
  432.     
  433.     messageID = -errorID -176;
  434.     GetIndString(&message,ErrorStringsID,messageID);
  435.     NumToString(errorID,&idNum);
  436.     NumToString(ProcessID,&pID);
  437.     ParamText(&message,&idNum,"\p",&pID);
  438.     aHit = xAlert(ProcErrorAlertID,NIL);
  439. }
  440.         
  441.  
  442.  
  443.  
  444.     
  445.